/*****************************************************************************/
/**
 *  @file   SPHFileList.cpp
 *  @author Naohisa Sakamoto
 */
/*----------------------------------------------------------------------------
 *
 *  Copyright (c) Visualization Laboratory, Kyoto University.
 *  All rights reserved.
 *  See http://www.viz.media.kyoto-u.ac.jp/kvs/copyright/ for details.
 *
 *  $Id$
 */
/*****************************************************************************/
#include "SPHFileList.h"
#include <kvs/Directory>
#include <kvs/FileList>
#include <kvs/Math>
#include <kvs/Value>


namespace
{

/*===========================================================================*/
/**
 *  @brief  Returns minimum components as vector.
 *  @param  a [in] vector a
 *  @param  b [in] vector b
 *  @return minimum components
 */
/*===========================================================================*/
kvs::Vector3d Min( const kvs::Vector3d& a, const kvs::Vector3d& b )
{
    return kvs::Vector3d(
        kvs::Math::Min( a[0], b[0] ),
        kvs::Math::Min( a[1], b[1] ),
        kvs::Math::Min( a[2], b[2] ) );
}

/*===========================================================================*/
/**
 *  @brief  Returns maximum components as vector.
 *  @param  a [in] vector a
 *  @param  b [in] vector b
 *  @return maximum components
 */
/*===========================================================================*/
kvs::Vector3d Max( const kvs::Vector3d& a, const kvs::Vector3d& b )
{
    return kvs::Vector3d(
        kvs::Math::Max( a[0], b[0] ),
        kvs::Math::Max( a[1], b[1] ),
        kvs::Math::Max( a[2], b[2] ) );
}

}


namespace kvsbloodvis
{

namespace util
{

/*===========================================================================*/
/**
 *  @brief  Constructs a new SPHFileList class.
 *  @param  dirname [in] director name
 *  @param  header_only [in] if true the header information will be only read
 */
/*===========================================================================*/
SPHFileList::SPHFileList( const std::string& dirname, bool header_only ):
    m_header_only( header_only )
{
    this->read( dirname );
}

/*===========================================================================*/
/**
 *  @brief  Constructs a new SPHFileList class.
 *  @param  files [in] list of files
 *  @param  header_only [in] if true the header information will be only read
 */
/*===========================================================================*/
SPHFileList::SPHFileList( const kvs::FileList& files, bool header_only ):
    m_header_only( header_only )
{
    this->read( files );
}

/*===========================================================================*/
/**
 *  @brief  Prints the file information.
 *  @param  os [in] output stream
 *  @param  indent [in] indent
 */
/*===========================================================================*/
void SPHFileList::print( std::ostream& os, const kvs::Indent& indent ) const
{
    os << indent << "Number of SPH files : " << m_sph_list.size() << std::endl;
    os << indent << "svType : " << m_sv_type << std::endl;
    os << indent << "dType : " << m_d_type << std::endl;
    os << indent << "IMAX : " << m_max[0] << std::endl;
    os << indent << "JMAX : " << m_max[1] << std::endl;
    os << indent << "KMAX : " << m_max[2] << std::endl;
    os << indent << "XORG : " << m_org[0] << std::endl;
    os << indent << "YORG : " << m_org[1] << std::endl;
    os << indent << "ZORG : " << m_org[2] << std::endl;
    os << indent << "XPITCH : " << m_pitch[0] << std::endl;
    os << indent << "YPITCH : " << m_pitch[1] << std::endl;
    os << indent << "ZPITCH : " << m_pitch[2] << std::endl;
    os << indent << "STEP : " << m_step << std::endl;
    os << indent << "TIME : " << m_time << std::endl;
}

/*===========================================================================*/
/**
 *  @brief  Reads the files store in the directory.
 *  @param  dirname [in] directory name
 *  @return true if the reading processing is done successfully
 */
/*===========================================================================*/
bool SPHFileList::read( const std::string& dirname )
{
    kvs::Directory dir( dirname );
    if ( !dir.exists() )
    {
        kvsMessageError( "Cannot open %s.", dirname.c_str() );
        return false;
    }

    return this->read( dir.fileList() );
}

/*===========================================================================*/
/**
 *  @brief  Reads the files.
 *  @param  files [in] list of files
 *  @return true if the reading processing is done successfully
 */
/*===========================================================================*/
bool SPHFileList::read( const kvs::FileList& files )
{
    kvs::Vector3d region_min = kvs::Vector3d::All( kvs::Value<kvs::Real64>::Max() );
    kvs::Vector3d region_max = kvs::Vector3d::All( kvs::Value<kvs::Real64>::Min() );

    kvs::FileList::const_iterator file = files.begin();
    kvs::FileList::const_iterator end = files.end();
    while ( file != end )
    {
        SPHFile sph( file->filePath( true ), m_header_only );
        if ( sph.isSuccess() )
        {
            m_sph_list.push_back( sph );

            kvs::Vector3d local_region_min = sph.org();
            kvs::Vector3d local_region_max = sph.org() + sph.max() * sph.pitch();
            region_min = ::Min( region_min, local_region_min );
            region_max = ::Max( region_max, local_region_max );
        }

        ++file;
    }

    m_sv_type = m_sph_list[0].svType();
    m_d_type = m_sph_list[0].dType();
    m_pitch = m_sph_list[0].pitch();
    m_max = ( region_max - region_min ) / m_pitch;
    m_org = region_min;
    m_step = m_sph_list[0].step();
    m_time = m_sph_list[0].time();

    return true;
}

} // end of namespace util

} // end of namespace kvsbloodvis
